package cn.com.aiouyi.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.slf4j.Logger;
import org.springframework.web.multipart.MultipartFile;

import lombok.extern.slf4j.Slf4j;

/**
 * Created by tommy on 2018/3/2.
 */
@Slf4j
public class FileHelper {

    private static final Logger logger = log;

    /**
     * 检查并纠正文件夹路径最后是否带了斜杠
     * */
    public static String rectifyFilepath(String filepath){
        if (!filepath.substring(filepath.length()-1, filepath.length()).equals("/") &&
                !filepath.substring(filepath.length()-1, filepath.length()).equals("/") ){
            filepath += File.separator;
        }
        return filepath;
    }
    
    public static void copyFile(String srcPath, String srcFilename,
                                String destPath, String destFilename, boolean readByOneByte) {
        srcPath = rectifyFilepath(srcPath);
        destPath = rectifyFilepath(destPath);
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(srcPath + srcFilename);
            File destPathFile = new File(destPath);
            if (!destPathFile.exists()){
                logger.info("目标文件夹路径：{}不存在，创建文件夹", destPath);
                destPathFile.mkdirs();
            }
            File file = new File(destPath + destFilename);
            if (!file.exists()) {
                file.createNewFile();
            }

            fos = new FileOutputStream(file);
            int ch;
            if (readByOneByte) {
                byte buffer[] = new byte[1];
                while ((ch = fis.read(buffer)) != -1) {
                    fos.write(buffer[0]);
                }
            } else {
                byte buffer[] = new byte[1024];
                while ((ch = fis.read(buffer)) != -1) {
                    for (int i = 0; i < ch; i++) {
                        fos.write(buffer[i]);
                    }
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fis.close();
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static boolean uploadFile(MultipartFile file, String dest, String finalFilename) {
        logger.info("开始上传文件到指定路径:{},最终文件名为：{}", dest, finalFilename);
        dest = rectifyFilepath(dest);
        File filepath = new File(dest);
        if (!filepath.exists()) {
            logger.info("文件夹路径：{} 不存在，创建文件夹", dest);
            filepath.mkdirs();
        }
        BufferedOutputStream bos = null;
        try {
            byte[] bytes = file.getBytes();
            bos = new BufferedOutputStream(
                    new FileOutputStream(new File(dest + finalFilename)));
            bos.write(bytes);
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    public static boolean deleteFile(String filepath, String filename, boolean isTempFile){
        filepath = rectifyFilepath(filepath);
        File file = new File(filepath + filename);
        if (file.exists()){
            if (!isTempFile) {
                //用于正常删除文件
                file.delete();
            } else {
                //用于删除临时文件
                //deleteOnExit在JVM退出时才删 不会立即删 一般用于删除临时文件
                file.deleteOnExit();
            }
            if (!isTempFile && !file.exists()){
                return true;
            }
        } else {
            logger.info("文件：{} 不存在", filepath);
        }
        return false;
    }

    /**
     * 存储序列化对象到文件
     * */
    public static boolean saveSerializeObject2File(String filepath, String filename, Object obj){
        filepath = rectifyFilepath(filepath);
        File file = new File(filepath);
        if (!file.exists()){
            logger.info("文件夹路径：{} 不存在，创建文件夹", filepath);
            file.mkdirs();
        }
        ObjectOutputStream oos = null;
        byte[] objectBytes = null;
        try {
            objectBytes = SerializeHelper.serialize(obj);
            oos = new ObjectOutputStream(new FileOutputStream(filepath + filename));
            oos.write(objectBytes);
            oos.flush();
            oos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        File file1 = new File(filepath + filename);
        if (file1.exists()){
            Object obj1 = SerializeHelper.deSerialize(objectBytes);
            if (obj.toString().equals(obj1.toString())){
                return true;
            } else {
                logger.info("序列化存储的对象({})与原来的({})不一致, 删除文件", obj1, obj);
                FileHelper.deleteFile(filepath, filename, false);
            }
        }
        logger.info("存储序列化对象 {} 失败", obj);
        return false;
    }

    /**
     * 从序列化文件中读取对象
     * */
    public static Object readObjectFromSerializedFile(String filepath, String filename){
        filepath = rectifyFilepath(filepath);
        File file = new File(filepath);
        if (!file.exists()){
            logger.info("文件夹路径：{} 不存在", filepath);
            return null;
        }
        try {
            FileInputStream fis = new FileInputStream(filepath + filename);
            ObjectInputStream ois = new ObjectInputStream(fis);
            Object obj1 = ois.readObject();
            ois.close();
            fis.close();
            return obj1;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取文件后缀名
     * */
    public static String getSuffix(String filename){
        if (filename.indexOf(".") != -1){
            return filename.substring(filename.lastIndexOf(".")+1, filename.length());
        }else{
            return null;
        }
    }


    /**
     * 文件类型是否符合
     * */
    public static boolean isValidSuffix(String filename, String suffixLimit){
        String suffix = getSuffix(filename).replace(".","");
        String[] suffixLimits = suffixLimit.split(",");
        if (Arrays.asList(suffixLimits).contains(suffix)){
            return true;
        }
        return false;
    }

    public void writeTo(File f, File newFile) throws IOException {
        FileInputStream fis = new FileInputStream(f);
        FileOutputStream fos = new FileOutputStream(newFile);
        try {
            byte[] buf = new byte[8192];
            do {
                int rc = fis.read(buf);
                if (rc == -1)
                    break;
                fos.write(buf, 0, rc);
                if (rc < buf.length)
                    break;
            } while (true);
        } finally {
            fis.close();
            fos.close();
        }
    }

    public List<String> getFiles(String s) {
        String regex = "src=[\"||'].[^\"]*[\"||']";

//String  regex="src=/"?(.*?)/"";也可
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(s);
        List<String> list = new ArrayList<String>();
        while (m.find()) {
            int start = m.start();
            int end = m.end();
            String temp = s.substring(start + 5, end - 1);
            logger.info(temp);
            list.add(temp);

            File file = new File(System.getProperty("user.dir")+ temp);
            if (file.exists()) {
                logger.info("deleted {}", temp);

                if (file.delete())
                    logger.info("success ");
                ;
            }

        }
        return list;
    }

    public void delete_oldimg(String filepath) {
        File f = new File(filepath);
        if (f.exists()) {
            logger.info("file exists");
            f.delete();
            //return "ok";
        } else {
            logger.info("file doesnot exists");
            //return "error";
        }

    }

    /*
   * 从别的controller中传入一个已经保存在最终目录的文件夹中的文件
   * 压缩图片 文件名与原文件名保持一致 但是保存到对应文件夹新建的"narrow"文件夹下
   * resizeTimes 压缩倍数 若为 1 则压缩到原来文件的100%大小 若为0.5则压缩到原来文件的50%大小
   *
   * */
//    public static boolean narrowImage(String srcPath, String srcFilename, String destPath, String destFilename,
//                                      Long limitSize, Float compressQuality) {
//        srcPath = rectifyFilepath(srcPath);
//        destPath = rectifyFilepath(destPath);
//        File srcFile = new File(srcPath + srcFilename);
//        if (!srcFile.exists()){
//            logger.info("文件："+ srcPath + srcFilename+" 不存在");
//            return false;
//        }
//        File destFileFolder = new File(destPath);
//        if (!destFileFolder.exists()){
//            logger.info("目标文件夹："+destPath+" 不存在，创建文件夹");
//        }
//        BufferedImage beforefile = null;//创建一个图片流
//        String oldfilename = srcFile.getName();
//        String oldfilepath = srcFile.getPath();
//        long oldfilesize = srcFile.length();
//        float compressionRatio = 1L;
//        if (oldfilesize > limitSize) {
//            compressionRatio = limitSize % oldfilesize;
//        } else{
//            logger.info("源文件："+oldfilesize+", 限制最大:"+limitSize+", 无需压缩");
//        }
//        logger.info("压缩前的图片名为:" + oldfilename + ",文件存放路径为：" + oldfilepath + ",文件原来的大小为："
//                + oldfilesize + ", 压缩后最大为："+ limitSize + ",压缩后需要存放到：" + destPath);
//
//        if (oldfilesize > 0) {
//            logger.info("文件存在！");
//            BufferedImage bi = null;
//            try {
//                bi = ImageIO.read(srcFile);
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//
//            float oldHeight = bi.getHeight();//原有文件的高度
//            float oldWidth = bi.getWidth();//原有文件的宽度
//
//            logger.info("height:" + oldHeight + ",width:" + oldWidth);
//
//            int newHighet = (int) (oldHeight * compressionRatio);
//            int newWidth = (int) (oldWidth * compressionRatio);
//            logger.info("newHighet" + newHighet);
//
//            beforefile = new BufferedImage(newWidth, newHighet, BufferedImage.TYPE_INT_RGB);
//            beforefile.getGraphics().drawImage(
//                    bi.getScaledInstance(newWidth, newHighet, Image.SCALE_SMOOTH), 0, 0, null);//绘制缩放后的图像流
//
//            logger.info("newimage:" + beforefile);
//
//
//            try {
//                FileOutputStream newimage = new FileOutputStream(destPath + destFilename);
//
//
//                JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(newimage);
//                JPEGEncodeParam jep = JPEGCodec.getDefaultJPEGEncodeParam(beforefile);
//                logger.info("压缩ing！");
//            /*
//            * 压缩质量
//            * */
//                jep.setQuality(compressQuality, true);
//                try {
//                    encoder.encode(beforefile, jep);
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            /*
//            * 近jpeg编码
//            * */
//                try {
//                    newimage.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//                logger.info("压缩后的图片：" + newimage);
//            } catch (FileNotFoundException e) {
//                e.printStackTrace();
//            }
//        }
//        return true;
//    }


    /**
     * 将存放在sourceFilePath目录下的源文件，打包成fileName名称的zip文件，并存放到zipFilePath路径下
     *
     * @param sourceFilePath :待压缩的文件路径
     * @param zipFilePath    :压缩后存放路径
     * @param fileName       :压缩后文件的名称
     * @return
     */
    public boolean fileToZip(String sourceFilePath, String zipFilePath, String fileName) {
        boolean flag = false;
        File sourceFile = new File(sourceFilePath);
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        ZipOutputStream zos = null;

        if (sourceFile.exists() == false) {
            logger.info("待压缩的文件目录：{} 不存在.", sourceFilePath);
        } else {
            try {
                File zipFile = new File(zipFilePath + "/" + fileName + ".zip");
                if (zipFile.exists()) {
                    logger.info(zipFilePath + "目录下存在名字为:{}.zip" + "打包文件.", fileName);
                    zipFile.delete();//先删除原文件再创建新的
                }
                File[] sourceFiles = sourceFile.listFiles();
                if (null == sourceFiles || sourceFiles.length < 1) {
                    logger.info("待压缩的文件目录：{} 里面不存在文件，无需压缩.", sourceFilePath);
                } else {
                    fos = new FileOutputStream(zipFile);
                    zos = new ZipOutputStream(new BufferedOutputStream(fos));
                    byte[] bufs = new byte[1024 * 10];
                    for (int i = 0; i < sourceFiles.length; i++) {
                        //创建ZIP实体，并添加进压缩包
                        ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());
                        zos.putNextEntry(zipEntry);
                        //读取待压缩的文件并写进压缩包里
                        fis = new FileInputStream(sourceFiles[i]);
                        bis = new BufferedInputStream(fis, 1024 * 10);
                        int read = 0;
                        while ((read = bis.read(bufs, 0, 1024 * 10)) != -1) {
                            zos.write(bufs, 0, read);
                        }
                    }
                    flag = true;
                }


            } catch (FileNotFoundException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } finally {
                //关闭流
                try {
                    if (null != bis) bis.close();
                    if (null != zos) zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
        }
        return flag;
    }

    /**
     * 将存放在sourceFilePath目录下的源文件,打包成fileName名称的ZIP文件,并存放到zipFilePath。
     * * @param sourceFilePath 待压缩的文件路径
     * * @param zipFilePath 压缩后存放路径
     * * @param fileName 压缩后文件的名称
     * * @return flag
     */

    public boolean fileToZipBetter(String sourceFilePath, String zipFilePath, String fileName) {
        boolean flag = false;
        File sourceFile = new File(sourceFilePath);
        if (sourceFile.exists() == false) {
            logger.info(">>>>>> 待压缩的文件目录：{} 不存在. <<<<<<", sourceFilePath);
            flag = false;
            return flag;
        } else {
            try {
                File zipFile = new File(zipFilePath + "/" + fileName + ".zip");
                if (zipFile.exists()) {
                    logger.info(">>>>>> {} 目录下存在名字为：{}.zip" + " 打包文件.需要先删除 <<<<<<", zipFilePath, fileName);
                    zipFile.delete();
                    logger.info("删除成功！");
                } else {
                    logger.info("删除失败！");
                }
                File[] sourceFiles = sourceFile.listFiles();
                if (null == sourceFiles || sourceFiles.length < 1) {
                    logger.info(">>>>>> 待压缩的文件目录：{} 里面不存在文件,无需压缩. <<<<<<", sourceFilePath);
                    flag = false;
                    return flag;
                } else {
                    ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));  //用到时才申明，否则容易出现问题，记得先开后关，后开先关
                    byte[] bufs = new byte[1024 * 10];
                    // 缓冲块
                    for (int i = 0; i < sourceFiles.length; i++) { // 创建ZIP实体,并添加进压缩包
                        ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());
                        zos.putNextEntry(zipEntry); // 读取待压缩的文件并写进压缩包里
                        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFiles[i]), 1024 * 10);    //用到时才申明，否则容易出现问题，记得先开后关，后开先关
                        int read = 0;
                        while ((read = (bis.read(bufs, 0, 1024 * 10))) != -1) {
                            zos.write(bufs, 0, read);
                        }
                        if (null != bis) bis.close();  //关闭
                    }
                    flag = true;
                    if (null != zos) zos.close();  //关闭
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
        return flag;
    }


    /**
     * 删除空目录
     *
     * @param dir 将要删除的目录路径
     */
    public void doDeleteEmptyDir(String dir) {
        boolean success = (new File(dir)).delete();
        if (success) {
            logger.info("Successfully deleted empty directory: {}", dir);
        } else {
            logger.info("Failed to delete empty directory: {}", dir);
        }
    }

    /**
     * 递归删除目录下的所有文件及子目录下所有文件
     *
     * @param dir 将要删除的文件目录
     * @return boolean Returns "true" if all deletions were successful.
     * If a deletion fails, the method stops attempting to
     * delete and returns "false".
     */
    public boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            //递归删除目录中的子目录下
            for (int i = 0; i < children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空，可以删除
        return dir.delete();
    }
}
